package com.jxtpro.generator;

import java.io.File;
import java.io.FileWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.sql.DataSource;
import javax.swing.filechooser.FileSystemView;

import com.jfinal.plugin.activerecord.dialect.Dialect;
import com.jfinal.plugin.activerecord.generator.ColumnMeta;
import com.jfinal.plugin.activerecord.generator.MetaBuilder;
import com.jfinal.plugin.activerecord.generator.TableMeta;
import com.jfinal.plugin.activerecord.generator.TypeMapping;
import com.jfinal.template.Engine;
import com.jfinal.template.Template;

/**
 * 
 * @author x
 */
public abstract class AbstractGenerator {
	
	private String fileSeparator = System.getProperty("file.separator");
	
	/**
	 * 数据库连接池
	 * @throws Exception
	 */
	abstract DataSource getDataSource(String url,String u,String p) throws Exception;
	/**
	 * 设置模板渲染引擎
	 * @return
	 */
	abstract Engine setEngine();
	/**
	 * 元数据映射 MetaBuilder
	 */
	abstract MetaBuilder getMetaBuilder(DataSource dataSource) throws Exception;
	/**
	 * 设置映射方言
	 * @param metaBuilder
	 * @return
	 */
	abstract void setMetaBuilderDialect(MetaBuilder metaBuilder,Dialect dialect);
	/**
	 * 获取映射方言
	 * @return
	 */
	abstract Dialect getDialect();
	/**
	 * 设置跳过 生成表
	 * @param metaBuilder
	 * @return
	 */
	abstract void setMetaBuilderExcludedTable(MetaBuilder metaBuilder,String[] excludedTables);
	/**
	 * 获取跳过表
	 * @return
	 */
	abstract String[] getExcludedTables();
	/**
	 * 设置java 类型映射
	 * @param metaBuilder
	 * @return
	 */
	abstract void setMetaBuilderTypeMapping(MetaBuilder metaBuilder,TypeMapping typeMapping);
	/**
	 * 获取java 类型映射
	 * @return
	 */
	abstract TypeMapping getTypeMapping();
	/**
	 * 设置java 类型映射
	 * @param metaBuilder
	 * @return
	 */
	abstract void setMetaBuilderRemovedTableNamePrefixes(MetaBuilder metaBuilder,String[] removedTableNamePrefixes);
	/**
	 * 获取java 类型映射
	 * @return
	 */
	abstract String[] getRemovedTableNamePrefixes();
	/**
	 * 获取表的元数据信息
	 * @return
	 * @throws Exception
	 */
	abstract List<TableMeta> getTableMetas(MetaBuilder metaBuilder) throws Exception;
	/**
	 * 获取在enjoy模板中使用的变量
	 * @return
	 */
	abstract Map<String,Object> setMetas(Map<String,Object> map);
	/**
	 * 获取表的字段元数据信息
	 * @return
	 * @throws Exception
	 */
	abstract List<ColumnMeta> getColumnMetas(TableMeta tableMeta) throws Exception;
	/**
	 * 执行本 代码生成器的主要任务
	 * @throws Exception
	 */
	abstract void doTask(Engine engine,List<TableMeta> tableMetas, Map<String,Object> content,List<List<String>> tempList) throws Exception;
	/**
	 * 读取配置文件
	 * @param pf
	 * @return
	 */
	public Map<String, Object> loadProperties(String pf) {
		ResourceBundle rb = ResourceBundle.getBundle(pf);
		Map<String, Object> map = new HashMap<String, Object>();
		Enumeration<String> enu = rb.getKeys();
		while (enu.hasMoreElements()) {
			String key = enu.nextElement();
			String value = rb.getString(key);
			map.put(key, value);
		}
		return map;
	}
	/**
	 * 生成代码文件
	 * @param template
	 * @param context
	 * @param fileName
	 * @param doPrint
	 * @throws Exception
	 */
	public void writeFiles(Template template, Map<String, Object> context, String fileName,boolean doPrint) throws Exception {
		FileWriter fileWriter = new FileWriter(fileName, false);
		template.render(context, fileWriter);
		fileWriter.close();
		if(doPrint){
			System.out.println("write File: " + fileName);
		}
	}
	

	/**
	 * 生成到桌面
	 * 
	 * @return
	 */
	public String toDesktop() {
		FileSystemView fsv = FileSystemView.getFileSystemView();
		File com = fsv.getHomeDirectory(); // 这便是读取桌面路径的方法了
		return com.getPath() + "/";
	}
	
	/**
	 * 输出src/main/java - 包 -路径下
	 * 
	 * @param out
	 * @return
	 */
	public String toOutJavaPath(String out,Map<String,Object> content) {
		String outPath = toDesktop() + content.get("projectName") + "/" + content.get("baseSrcPath")
				+ String.valueOf(content.get("projectPackage")).replace(".", fileSeparator) + "/" + out + "/";

		existFileSys(outPath);
		return outPath;
	}
	
	/**
	 * 检查创建文件
	 * 
	 * @param outPath
	 * @return
	 */
	public boolean existFileSys(String outPath) {
		File file = new File(outPath);
		if (!file.exists()) {
			file.mkdirs();
		}
		return true;
	}
	/**
	 * 输出到resources目录下 TODO 待实现
	 * 
	 * @param out
	 * @return
	 */
	public String toOutResourcesPath(String out,Map<String,Object> content) {
		String outPath = toDesktop() + content.get("projectName") + "/" + content.get("baseResourcesPath") + out;
		existFileSys(outPath);
		return outPath;
	}
	
	/**
	 * 输出到webapp目录下 TODO 待完成
	 * 
	 * @param out
	 * @return
	 */
	public String toOutWebApp(String out,Map<String,Object> content) {
		String outPath = toDesktop() + content.get("projectName") + "/" + content.get("baseWebAppPath") + out;
		existFileSys(outPath);
		return outPath;
	}
	
	/**
	 * 输出到WEB-INF目录下
	 * 
	 * @param out
	 * @return
	 */
	public String toOutWEBINF(String out,Map<String,Object> content) {
		String outPath = toDesktop() + content.get("projectName") + "/" + content.get("baseWEBINFPath") + out + "/";
		existFileSys(outPath);
		return outPath;
	}

	/**
	 * 输出java路径下
	 * 
	 * @param out
	 * @return
	 */
	public String toOutSrcPath(String out,Map<String,Object> content) {
		String outPath = toDesktop() + content.get("projectName") + "/" + out;
		existFileSys(outPath);
		return outPath;
	}
	

	
	public final void build(String url,String u,String p,String properties,List<List<String>> tempList){
		try{
			Engine engine = setEngine();
			if(engine == null){
				System.out.println("模板初始化 - 失败,程序结束...");
				return;
			}
			System.out.println("模板初始化成功...");
			DataSource ds = getDataSource(url, u, p);
			if(ds == null){
				System.out.println("无数据库连接池信息,检查连接信息或进行无连接操作...");
			}
			MetaBuilder metaBuilder = getMetaBuilder(ds);
			if(metaBuilder == null){
				System.out.println("无数据库元数据信息,进行无数据库操作...");
			}
			
			setMetaBuilderDialect(metaBuilder,getDialect());
			setMetaBuilderTypeMapping(metaBuilder, getTypeMapping());
			setMetaBuilderExcludedTable(metaBuilder,getExcludedTables());
			setMetaBuilderRemovedTableNamePrefixes(metaBuilder, getRemovedTableNamePrefixes());
			
			List<TableMeta> tableMetas = getTableMetas(metaBuilder);
			if(tableMetas == null){
				System.out.println("无表元数据信息,进行无表元数据操作...");
			}
			Map<String,Object> content = loadProperties(properties);
			setMetas(content);
			System.out.println("开始执行模板渲染,生成文件...");
			doTask(engine,tableMetas,content,tempList);
			System.out.println("执行模板渲染,生成文件结束...");
		 }catch(Exception e){
			e.printStackTrace();
			System.out.println("生成失败,程序结束...");
		}
	}
}
